﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO.Pipes;
using Common;
using Microsoft.Win32.SafeHandles;
using System.Reflection;

namespace NamedPipe.Server
{
    public sealed class ServerConnect
    {
        #region Fields

        private NamedPipeServerStream pipeServer;
        private static string _caminhoRules;

        #endregion

        #region Constructor

        public ServerConnect(string caminhoRules)
        {
            _caminhoRules = caminhoRules;
            this.pipeServer = null;
            Atributos.StructVariable = new Dictionary<string, Dictionary<string, List<MethodFxCop>>>();
            AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
        }

        #endregion

        #region Event Handle

        private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
        {
            Assembly assembly = null;
            string serializationAssemblyPartialName = "NamedPipe";

            if (args.Name.IndexOf(serializationAssemblyPartialName) != -1)
            {                
                string sSerializersDLL = string.Concat(serializationAssemblyPartialName, ".dll");
                string smartDeploymentHostLocation = _caminhoRules;
                assembly = Assembly.LoadFrom(Path.Combine(smartDeploymentHostLocation, sSerializersDLL));
            }

            return assembly;
        }

        #endregion

        public void ActiveServer()
        {
            this.pipeServer = new NamedPipeServerStream("FxCopPipe", PipeDirection.InOut, 254, PipeTransmissionMode.Message, PipeOptions.Asynchronous);
            this.pipeServer.BeginWaitForConnection(new AsyncCallback(Connect), "FxCop");
        }

        public void Stop()
        {
            this.pipeServer.Close();
            this.pipeServer.Dispose();
        }

        private void Connect(IAsyncResult ar)
        {
            try
            {
                this.pipeServer.EndWaitForConnection(ar);


                if (this.pipeServer.IsConnected)
                {
                    using (StreamReader sr = new StreamReader(this.pipeServer))
                    {
                        string temp;
                        while ((temp = sr.ReadLine()) != null)
                        {
                            this.SetAttributes(temp);
                        }
                    }


                    this.pipeServer = null;
                    this.pipeServer = new NamedPipeServerStream("FxCopPipe", PipeDirection.InOut, 254, PipeTransmissionMode.Message, PipeOptions.Asynchronous);
                    this.pipeServer.BeginWaitForConnection(new AsyncCallback(Connect), null);
                }
            }
            catch
            {
                //Tentativa de conexão não foi bem sucedida.
                //throw;
            }
        }

        private Object DeserializeString(String str)
        {
            byte[] memorydata = null;
            MemoryStream rs = null;
            
            try
            {
                memorydata = Convert.FromBase64String(str);
                rs = new MemoryStream(memorydata);
                BinaryFormatter sf = new BinaryFormatter();

                return sf.Deserialize(rs);
            }
            catch (Exception ex)
            {
                return null;
            }
            finally
            {
                rs.Dispose();
            }
        }

        private void SetAttributes(String attributes)
        {
            string _namespace = string.Empty;
            string _class = string.Empty;
            MethodFxCop _methodFxCop = null;
            List<MethodFxCop> listMethod = null;
            List<VariableFxCop> variables = null;
            Dictionary<String, List<MethodFxCop>> dicClass = null;
            string[] methodProperties = null;
            string[] variableProperties = null;

            try
            {
                variables = new List<VariableFxCop>();

                foreach (String att in attributes.Split(Atributos.DIVIDE_MEMBERS))
                {
                    if (att.Contains(Atributos.NAMESPACE))
                    {
                        _namespace = att.Replace(Atributos.NAMESPACE, "");
                    }
                    else if (att.Contains(Atributos.CLASS))
                    {
                        _class = att.Replace(Atributos.CLASS, "");
                    }
                    else if (att.Contains(Atributos.METHOD))
                    {
                        methodProperties = att.Replace(Atributos.METHOD, "").Split(Atributos.DIVIDE_PROPERTIES);
                    }
                    else if (att.Contains(Atributos.VARIABLES))
                    {
                        foreach (String variable in att.Replace(Atributos.VARIABLES, "").Split(Atributos.DIVIDE_VARIABLES))
                        {
                            variableProperties = variable.Split(Atributos.DIVIDE_PROPERTIES);

                            if(variableProperties.Count() == 2)
                                variables.Add(new VariableFxCop(variableProperties.GetValue(0).ToString(), variableProperties.GetValue(1).ToString()));
                        }
                    }
                }

                Int32? lines = null;

                if (methodProperties.Count() == 2 && variables != null)
                {
                    if (methodProperties.GetValue(1) != null)
                        lines = Convert.ToInt32(methodProperties.GetValue(1));
                    
                    _methodFxCop = new MethodFxCop(methodProperties.GetValue(0).ToString(), lines, variables);
                }
                
                listMethod = new List<MethodFxCop>();
                dicClass = new Dictionary<string, List<MethodFxCop>>();

                if (_methodFxCop != null)
                {
                    listMethod.Add(_methodFxCop);

                    if (Atributos.StructVariable.Keys.Contains(_namespace) &&
                        Atributos.StructVariable[_namespace].Keys.Contains(_class))
                    {
                        Atributos.StructVariable[_namespace][_class].Add(_methodFxCop);
                    }
                    else if (Atributos.StructVariable.Keys.Contains(_namespace))
                    {
                        Atributos.StructVariable[_namespace].Add(_class, listMethod);
                    }
                    else
                    {
                        dicClass.Add(_class, listMethod);
                        Atributos.StructVariable.Add(_namespace, dicClass);
                    }
                }
            }
            catch
            {
                throw;
            }
        }

        //private void SetAttributes(Object[] attributes)
        //{
        //    string _namespace;
        //    string _class;
        //    MethodFxCop _methodFxCop;
        //    List<MethodFxCop> listMethod;
        //    Dictionary<String, List<MethodFxCop>> dicClass;

        //    try
        //    {
        //        if (attributes.Count() == 3)
        //        {
        //            _namespace = attributes.GetValue(0).ToString();
        //            _class = attributes.GetValue(1).ToString();
        //            _methodFxCop = attributes.GetValue(2) as MethodFxCop;
        //            listMethod = new List<MethodFxCop>();
        //            dicClass = new Dictionary<string, List<MethodFxCop>>();

        //            listMethod.Add(_methodFxCop);

        //            if (Atributos.StructVariable.Keys.Contains(_namespace) &&
        //                Atributos.StructVariable[_namespace].Keys.Contains(_class))
        //            {
        //                Atributos.StructVariable[_namespace][_class].Add(_methodFxCop);
        //            }
        //            else if (Atributos.StructVariable.Keys.Contains(_namespace))
        //            {
        //                Atributos.StructVariable[_namespace].Add(_class, listMethod);
        //            }
        //            else
        //            {
        //                dicClass.Add(_class, listMethod);
        //                Atributos.StructVariable.Add(_namespace, dicClass);
        //            }
        //        }
        //    }
        //    catch (Exception ex)
        //    {
        //        //Implementar
        //    }
        //}
    }
}
